using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Linq;
using GameFramework;
using UnityEngine.Android;
using UnityGameFramework.Runtime;

namespace LS.GameSystem
{
    public class GameSystemManager : IGameSystemManager
    {

        private GameFrameworkLinkedList<GameSystemBase> m_SystemsLinkedList = null;
        private Dictionary<TypeNamePair, GameSystemBase> m_SystemsDictionary = null;

        public GameSystemManager()
        {
            m_SystemsLinkedList = new GameFrameworkLinkedList<GameSystemBase>();
            m_SystemsDictionary = new Dictionary<TypeNamePair, GameSystemBase>();
        }

        /// <summary>
        /// 获取控制器
        /// </summary>
        /// <param name="systemType"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public GameSystemBase GetSystem(Type systemType, string name)
        {
            TypeNamePair tnp = new TypeNamePair(systemType, name);
            if (m_SystemsDictionary.TryGetValue(tnp, out var value))
            {
                return value;
            }
            return null;
        }

        /// <summary>
        /// 获取控制器
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public T GetSystem<T>(string name) where T : GameSystemBase, new()
        {
            return GetSystem(typeof(T), name) as T;
        }

        public GameSystemBase[] GetAllSystems()
        {
            return m_SystemsDictionary.Values.ToArray();
        }

        /// <summary>
        /// 是否存在控制器
        /// </summary>
        /// <param name="system"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public bool HasSystem(GameSystemBase system)
        {
            return m_SystemsDictionary.ContainsValue(system);
        }

        /// <summary>
        /// 是否存在控制器
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public bool HasSystem<T>(string name)
            where T: GameSystemBase, new()
        {
            TypeNamePair tnp = new TypeNamePair(typeof(T), name);
            return m_SystemsDictionary.ContainsKey(tnp);
        }

        /// <summary>
        /// 注册控制器
        /// </summary>
        /// <param name="lsSystem"></param>
        /// <exception cref="NotImplementedException"></exception>
        public void RegisterSystem(GameSystemBase lsSystem)
        {
            Type type = lsSystem.GetType();
            string name = lsSystem.Name;
            TypeNamePair tnp = new TypeNamePair(type, name);
            RegistControllerInternal(tnp, lsSystem);
        }

        /// <summary>
        /// 注册控制器
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public T RegisterSystem<T>(string name) where T : GameSystemBase, new()
        {
            return (T)RegisterSystem(typeof(T), name);
        }

        /// <summary>
        /// 注册控制器
        /// </summary>
        /// <param name="controllerType"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public GameSystemBase RegisterSystem(Type controllerType, string name)
        {
            GameSystemBase ctrl = (GameSystemBase)Activator.CreateInstance(controllerType);
            TypeNamePair tnp = new TypeNamePair(controllerType, name);
            RegistControllerInternal(tnp, ctrl);
            return ctrl;
        }

        /// <summary>
        /// 移除控制器
        /// </summary>
        /// <param name="ilsSystem"></param>
        /// <exception cref="NotImplementedException"></exception>
        public void RemoveSystem(GameSystemBase ilsSystem)
        {
            RemoveSystem(ilsSystem.GetType(), ilsSystem.Name);
        }

        /// <summary>
        /// 移除控制器
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name"></param>
        /// <exception cref="NotImplementedException"></exception>
        public void RemoveSystem<T>(string name) where T : GameSystemBase, new()
        {
            RemoveSystem(typeof(T), name);
        }

        /// <summary>
        /// 移除控制器
        /// </summary>
        /// <param name="controllerType"></param>
        /// <param name="name"></param>
        public void RemoveSystem(Type controllerType, string name)
        {
            TypeNamePair tnp = new TypeNamePair(controllerType, name);
            RemoveControllerInternal(tnp);
        }

        /// <summary>
        /// 关闭控制器管理
        /// </summary>
        public void Shutdown()
        {
            var node = m_SystemsLinkedList.First;
            while (node != null)
            {
                node.Value.Shutdown();
                node = node.Next;
            }
            m_SystemsLinkedList.Clear();
            m_SystemsDictionary.Clear();
        }

        /// <summary>
        /// 轮询控制器
        /// </summary>
        /// <param name="deltaSeconds">帧间隔时间</param>
        /// <param name="realDeltaSeconds">真实帧间隔时间</param>
        /// <param name="time">总经过时间</param>
        /// <param name="unscaledTime">未缩放的总经过时间</param>
        public void Update(float deltaSeconds, float realDeltaSeconds)
        {
            var node = m_SystemsLinkedList.First;
            while (node != null)
            {
                node.Value.Update(deltaSeconds, realDeltaSeconds);
                node = node.Next;
            }
        }

        public void FixedUpdate(float fixedDeltaSeconds, float realFixedDeltaSeconds)
        {
            var node = m_SystemsLinkedList.First;
            while (node != null)
            {
                node.Value.FixedUpdate(fixedDeltaSeconds, realFixedDeltaSeconds);
                node = node.Next;
            }
        }

        /// <summary>
        /// 每秒轮询控制器
        /// </summary>
        /// <param name="seconds"></param>
        public void UpdateSeconds(int seconds)
        {
            var node = m_SystemsLinkedList.First;
            while (node != null)
            {
                node.Value.UpdateSeconds(seconds);
                node = node.Next;
            }
        }

        public void UpdateRealSeconds(int realSeconds)
        {
            var node = m_SystemsLinkedList.First;
            while (node != null)
            {
                node.Value.UpdateRealSeconds(realSeconds);
                node = node.Next;
            }
        }

        private void RegistControllerInternal(TypeNamePair key, GameSystemBase ilsSystem)
        {
            if (m_SystemsDictionary.ContainsKey(key))
            {
                throw new LSRuntimeException($"Register Controller Exception: Type {{{key.Type.FullName}}} with name {{{key.Name}}} is exist, can not register agan!");
            }
            ilsSystem.Name = key.Name;
            m_SystemsDictionary.Add(key, ilsSystem);
            
            var node = m_SystemsLinkedList.First;
            while (node != null)
            {
                if (ilsSystem.Priority > node.Value.Priority)
                {
                    break;
                }
                node = node.Next;
            }

            if (node == null)
            {
                m_SystemsLinkedList.AddLast(ilsSystem);
            }
            else
            {
                m_SystemsLinkedList.AddBefore(node, ilsSystem);
            }
            
            try
            {
                ilsSystem.Init();
            }
            catch (Exception e)
            {
                Log.Error(e);
            }
        }

        private void RemoveControllerInternal(TypeNamePair key)
        {
            if (m_SystemsDictionary.TryGetValue(key,out var controller))
            {
                try
                {
                    controller.Shutdown();
                }
                catch (Exception e)
                {
                    Log.Error(e);
                }
                m_SystemsDictionary.Remove(key);
                m_SystemsLinkedList.Remove(controller);
            }
        }
    }
}
